# Copyright (c) 2011, 2012 Nathan Grubb
# Available under the new BSD license; see LICENSE.txt

"""plugin/dispatch.py: Completely internal plugin used to respond to state changes
   in response to IRC messages.
"""

class Dispatch(object):
    """Methods used to respond to IRC messages and adjust state accordingly."""

    commands = ("ping", "353", "error", "join", "part", "kick", "quit", "nick",)
    name = "Dispatch"
    desc = "Internal plugin to handle state change responses for IRC messages."
    permissions = None
    type = "irc"

    def __init__(self, api, msg):
        self.api = api
        self.msg = msg

    def command_ping(self):
        self.api.grubbot.connection.send("pong", self.msg.args[0])

    ## Methods for managing the user state

    def command_353(self):
        """Numeric 353 sends a list of all users in a channel as you join the
           channel. If the bot was previously in the channel this session, the
           the previous data is replaced anyway.
        """

        channel = self.msg.args[2]
        # Also strip  relevant first characters
        users = [user.lstrip("@+") for user in self.msg.args[3].split()]

        if channel in self.api.grubbot.users:
            del self.api.grubbot.users[channel]
        self.api.grubbot.users[channel] = users

    def command_error(self):
        """The ERROR command is sent to a client right when the connection is
           closed.
        """
        
        self.api.grubbot.exit()

    def command_join(self):
        channel = self.msg.args[0]
        nickname = self.msg.nickname
        # BUGFIX The bot will crash on startup as the first person to join a
        # channel without this
        self.api.grubbot.users.setdefault(channel, []).append(nickname)

    def command_part(self):
        channel = self.msg.args[0]
        nickname = self.msg.nickname

        # After the bot leaves a channel, it stops tracking its users.
        if nickname == self.api.grubbot.nickname:
            del self.api.grubbot.users[channel]
        else:
            self.api.grubbot.users[channel].remove(nickname)

        if nickname not in self.api.grubbot.users:            
            # Logout the user
            if nickname in self.api.grubbot.sessions:
                del self.api.grubbot.sessions[nickname]

    def command_kick(self):
        channel = self.msg.args[0]
        nickname = self.msg.args[1]

        # After the bot leaves a channel, it stops tracking its users.
        if nickname == self.api.grubbot.nickname:
            del self.api.grubbot.users[channel]
        else:
            self.api.grubbot.users[channel].remove(nickname)

    def command_quit(self):
        nickname = self.msg.nickname

        # Logout the user
        if nickname in self.api.grubbot.sessions:
            del self.api.grubbot.sessions[nickname]

        # Since quit messages don't specify channels, this calculate the channels
        # the nickname are in.
        channels = []
        for channel, nicknames in self.api.grubbot.users.items():
            if nickname in nicknames:
                channels.append(channel)

        # BUGFIX/HACK: Used to fix a bug in the logging module where QUIT logging would
        # attempt to get a list of users in a channel, but got an empty list because this
        # function deleted it first.
        import logging

        log = logging.plugin(self.api, self.msg)
        log.command_quit()

        for channel in channels:
            self.api.grubbot.users[channel].remove(nickname)

    def command_nick(self):
        """Watches user nickname state changes."""

        nickname = self.msg.nickname
        new_nickname = self.msg.args[0]

        for users in self.api.grubbot.users.values():
            if nickname in users:
                users.remove(nickname)
                users.append(new_nickname)

                # Allows Grubbot to track nick changes of logged in users                
                if nickname in self.api.grubbot.sessions:
                    self.api.grubbot.sessions[new_nickname] = self.api.grubbot.sessions[nickname]
                    del self.api.grubbot.sessions[nickname]

        # Take note if the bot's name changes
        if nickname == self.api.grubbot.nickname:
            self.api.grubbot.nickname = new_nickname

plugin = Dispatch